package com.android.manghe.view;

import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;

import com.android.base.tools.Glide.GlideHelper;
import com.android.manghe.R;
import com.android.manghe.box.model.BoxModel;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;

/**
 * author : liuwen
 * e-mail : liuwen370494581@163.com
 * time   : 2021/12/08 15:24
 * desc   :
 */
public class BubbleView extends RelativeLayout {
    private List<BoxModel.DataBean.GoodsListBean> drawableList = new ArrayList<>();

    private int viewWidth = dp2pix(16), viewHeight = dp2pix(16);
//    private int viewWidth = dp2pix(60), viewHeight = dp2pix(120);

    private int maxHeartNum = 8;
    private int minHeartNum = 2;

    private int riseDuration = 4000;

    private int bottomPadding = 200;
    private int originsOffset = 60;

    private float maxScale = 1.0f;
    private float minScale = 1.0f;

    private int innerDelay = 20;
    private ImageView mGiftImageView;
    private Context mContext;
    private ValueAnimator valueAnimator;
    private Disposable disposable;
    private int count = 0;


    public BubbleView(Context context) {
        super(context);
        this.mContext = context;
    }

    public BubbleView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
    }

    public BubbleView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext = context;
    }

    public BubbleView setDrawableList(List<BoxModel.DataBean.GoodsListBean> drawableList) {
        this.drawableList = drawableList;
        return this;
    }

    public BubbleView setRiseDuration(int riseDuration) {
        this.riseDuration = riseDuration;
        return this;
    }

    public BubbleView setBottomPadding(int px) {
        this.bottomPadding = px;
        return this;
    }

    public BubbleView setOriginsOffset(int px) {
        this.originsOffset = px;
        return this;
    }

    public BubbleView setScaleAnimation(float maxScale, float minScale) {
        this.maxScale = maxScale;
        this.minScale = minScale;
        return this;
    }

    public BubbleView setAnimationDelay(int delay) {
        this.innerDelay = delay;
        return this;
    }

    public BubbleView setMaxHeartNum(int maxHeartNum) {
        this.maxHeartNum = maxHeartNum;
        return this;
    }

    public BubbleView setMinHeartNum(int minHeartNum) {
        this.minHeartNum = minHeartNum;
        return this;
    }

    public BubbleView setItemViewWH(int viewWidth, int viewHeight) {
        this.viewHeight = viewHeight;
        this.viewWidth = viewWidth;
        return this;
    }

    public BubbleView setGiftBoxImage(Drawable drawable, int positionX, int positionY) {
        mGiftImageView = new ImageView(getContext());
        mGiftImageView.setImageDrawable(drawable);
        LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        this.addView(mGiftImageView, layoutParams);
        mGiftImageView.setX(positionX);
        mGiftImageView.setY(positionY);
        return this;
    }

    @SuppressLint("CheckResult")
    public void startAnimation(final int rankWidth, final int rankHeight) {
        disposable = Observable.timer(innerDelay, TimeUnit.MILLISECONDS)
                .repeat((int) (Math.random() * (maxHeartNum - minHeartNum)) + minHeartNum)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(Long aLong) throws Exception {
                        bubbleAnimation(rankWidth, rankHeight);
                    }
                });
    }

    @SuppressLint("CheckResult")
    public void startAnimation(final int rankWidth, final int rankHeight, int count) {
        disposable = Observable.timer(1500, TimeUnit.MILLISECONDS)
                .repeat(count)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(Long aLong) throws Exception {
                        bubbleAnimation(rankWidth, rankHeight);
                    }
                });

    }

    @SuppressLint("CheckResult")
    public void startAnimation(final int rankWidth, final int rankHeight, int delay, int count) {
        Observable.timer(delay, TimeUnit.MILLISECONDS)
                .repeat(count)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(Long aLong) throws Exception {
                        bubbleAnimation(rankWidth, rankHeight);
                    }
                });
    }

    private void bubbleAnimation(int rankWidth, int rankHeight) {
        try {
            rankHeight -= bottomPadding;
            int seed = (int) (Math.random() * 3);
            switch (seed) {
                case 0:
                    rankWidth -= originsOffset;
                    break;
                case 1:
                    rankWidth += originsOffset;
                    break;
                case 2:
                    rankHeight -= originsOffset;
                    break;
            }

            int heartDrawableIndex;
            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(viewWidth, viewHeight);
//        heartDrawableIndex = (int) (drawableList.size() * Math.random());
            View view = LayoutInflater.from(mContext).inflate(R.layout.item_pao_pao, null, false);
            ImageView imageView = view.findViewById(R.id.id_img);
            if(drawableList.size()>0){
                setImgGift(imageView, drawableList.get(count));
                addView(view, layoutParams);
                count++;
                if (count == drawableList.size()) {
                    count = 0;
                }

                ObjectAnimator riseAlphaAnimator = ObjectAnimator.ofFloat(view, "alpha", 1.0f, 0.0f);
                riseAlphaAnimator.setDuration(riseDuration);

                ObjectAnimator riseScaleXAnimator = ObjectAnimator.ofFloat(view, "scaleX", minScale, maxScale);
                riseScaleXAnimator.setDuration(riseDuration);

                ObjectAnimator riseScaleYAnimator = ObjectAnimator.ofFloat(view, "scaleY", minScale, maxScale);
                riseScaleYAnimator.setDuration(riseDuration);

                valueAnimator = getBesselAnimator(view, rankWidth, rankHeight);
                AnimatorSet animatorSet = new AnimatorSet();
                animatorSet.play(valueAnimator).with(riseAlphaAnimator).with(riseScaleXAnimator).with(riseScaleYAnimator);
                animatorSet.start();
            }

        }catch (IndexOutOfBoundsException e){
            e.printStackTrace();
        }

    }

    private ValueAnimator getBesselAnimator(final View imageView, int rankWidth, int rankHeight) {
        float point0[] = new float[2];
        point0[0] = rankWidth / 2;
        point0[1] = rankHeight;

        float point1[] = new float[2];
        point1[0] = (float) ((rankWidth) * (0.10)) + (float) (Math.random() * (rankWidth) * (0.8));
        point1[1] = (float) (rankHeight - Math.random() * rankHeight * (0.5));

        float point2[] = new float[2];
        point2[0] = (float) (Math.random() * rankWidth);
        point2[1] = (float) (Math.random() * (rankHeight - point1[1]));

        float point3[] = new float[2];
        point3[0] = (float) (Math.random() * rankWidth);
        point3[1] = 0;

        BesselEvaluator besselEvaluator = new BesselEvaluator(point1, point2);
        ValueAnimator valueAnimator = ValueAnimator.ofObject(besselEvaluator, point0, point3);
        valueAnimator.setDuration(riseDuration);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float[] currentPosition = new float[2];
                currentPosition = (float[]) animation.getAnimatedValue();
                imageView.setTranslationX(currentPosition[0]);
                imageView.setTranslationY(currentPosition[1]);
            }
        });
        valueAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {

            }

            @Override
            public void onAnimationEnd(Animator animation) {
                removeView(imageView);

            }

            @Override
            public void onAnimationCancel(Animator animation) {

            }

            @Override
            public void onAnimationRepeat(Animator animation) {

            }
        });
        return valueAnimator;
    }

    public void stop() {
        count = 0;
        if (valueAnimator != null) {
            valueAnimator.cancel();
            removeAllViews();
        }
        //取消注册
        if (disposable != null) {
            disposable.dispose();
        }
    }

    private void setImgGift(ImageView img, BoxModel.DataBean.GoodsListBean item) {
        GlideHelper.loadWithHolderErr(mContext, item.thumb, img);
    }

    public class BesselEvaluator implements TypeEvaluator<float[]> {
        private float point1[] = new float[2], point2[] = new float[2];

        public BesselEvaluator(float[] point1, float[] point2) {
            this.point1 = point1;
            this.point2 = point2;
        }

        @Override
        public float[] evaluate(float fraction, float[] point0, float[] point3) {
            float[] currentPosition = new float[2];
            currentPosition[0] = point0[0] * (1 - fraction) * (1 - fraction) * (1 - fraction)
                    + point1[0] * 3 * fraction * (1 - fraction) * (1 - fraction)
                    + point2[0] * 3 * (1 - fraction) * fraction * fraction
                    + point3[0] * fraction * fraction * fraction;
            currentPosition[1] = point0[1] * (1 - fraction) * (1 - fraction) * (1 - fraction)
                    + point1[1] * 3 * fraction * (1 - fraction) * (1 - fraction)
                    + point2[1] * 3 * (1 - fraction) * fraction * fraction
                    + point3[1] * fraction * fraction * fraction;
            return currentPosition;
        }
    }

    private int dp2pix(int dp) {
        float scale = getResources().getDisplayMetrics().density;
        int pix = (int) (dp * scale + 0.5f);
        return pix;
    }

    private int pix2dp(int pix) {
        float scale = getResources().getDisplayMetrics().density;
        int dp = (int) (pix / scale + 0.5f);
        return dp;
    }
}
